package org.hitchhike.core.service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.hitchhike.common.service.BaseService;
import org.hitchhike.core.domain.Cities;
import org.hitchhike.core.domain.Order;
import org.hitchhike.core.domain.Provinces;
import org.hitchhike.core.domain.User;
import org.hitchhike.core.enums.Constant;
import org.hitchhike.core.form.OrderForm;
import org.hitchhike.core.repository.OrderRepository;
import org.hitchhike.core.utils.PageableUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

@Service
public class OrderService extends BaseService<Order, Long> {

  @Autowired
  private OrderRepository getOrderRepository() {
    return (OrderRepository) baseRepository;
  }

  @Autowired
  private OrderDetailService orderDetailService;

  public Order save(Order t) {
    User user = t.getUser();
    if (user.getUserType() == Constant.TYPE_1) {
      t.setOrderType(Constant.TYPE_1);
    } else if (user.getUserType() == Constant.TYPE_2) {
      t.setOrderType(Constant.TYPE_2);
    }
    t.setOrderState(Constant.ORDER_STATE_1);
    t.setOrderProcess(Constant.ORDER_PROCESS_0);
    return super.save(t);
  }

  public Page<Order> findAll(Integer page, Long userId, String orderState) {
    if (userId == null) {
      return null;
    }
    if (orderState == null) {
      return null;
    }

    Set<Integer> orderStates = new HashSet<Integer>();
    if (orderState.equals("12")) {
      orderStates.add(1);
      orderStates.add(2);
    } else if (orderState.equals("03")) {
      orderStates.add(0);
      orderStates.add(3);
    } else {
      return null;
    }

    return getOrderRepository().findByUserId(userId, orderStates,
        PageableUtil.getPageable(page, 10));
  }

  public Page<Order> findPageTochepiao(Integer page, final OrderForm orderForm) {
    return getOrderRepository().findAll(new Specification<Order>() {
      @Override
      public Predicate toPredicate(Root<Order> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        List<Predicate> predicates = new ArrayList<Predicate>();

        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (user.getUserType() == Constant.TYPE_1) {
          predicates.add(cb.equal(root.<String>get("orderType"), Constant.TYPE_2));
        } else if (user.getUserType() == Constant.TYPE_2) {
          predicates.add(cb.equal(root.<String>get("orderType"), Constant.TYPE_1));
        }

        predicates.add(cb.equal(root.<String>get("orderState"), Constant.ORDER_STATE_1));

        if (StringUtils.hasText(orderForm.getStartProvinces())
            && StringUtils.hasText(orderForm.getStartCities())) {
          predicates.add(cb.equal(root.<Provinces>get("startProvinces").<String>get("provinceid"),
              orderForm.getStartProvinces()));
          predicates.add(cb.equal(root.<Cities>get("startCities").<String>get("cityid"),
              orderForm.getStartCities()));
        }

        if (StringUtils.hasText(orderForm.getStopProvinces())
            && StringUtils.hasText(orderForm.getStopCities())) {
          predicates.add(cb.equal(root.<Provinces>get("stopProvinces").<String>get("provinceid"),
              orderForm.getStopProvinces()));
          predicates.add(cb.equal(root.<Cities>get("stopCities").<String>get("cityid"),
              orderForm.getStopCities()));
        }

        if (StringUtils.hasText(orderForm.getGoDate())) {
          predicates.add(cb.equal(root.<String>get("goDate"), orderForm.getGoDate()));
        }

        return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
      }
    }, PageableUtil.getPageable(page, 10));
  }

  /**
   * 获取首页的数据
   * 
   * @return
   */
  public List<Order> findToFrontMain() {
    Pageable pageable = new PageRequest(0, 20);
    int orderType = Constant.TYPE_0;

    User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    if (user.getUserType() == Constant.TYPE_1) {
      orderType = Constant.TYPE_2;
    } else if (user.getUserType() == Constant.TYPE_2) {
      orderType = Constant.TYPE_1;
    }

    Page<Order> page = getOrderRepository().findPageByOrderTypeAndOrderState(pageable, orderType,
        Constant.ORDER_STATE_1);
    return page.getContent();
  }

  @Transactional
  public void updateCancel(Long id) {
    Order order = super.get(id);
    order.setOrderState(Constant.ORDER_STATE_0);
    super.update(order);

    orderDetailService.updateCancel(id);
  }

  @Transactional
  public void updateConfirm(Long id) {
    Order order = super.get(id);
    order.setOrderState(Constant.ORDER_STATE_2);
    order.setOrderProcess(Constant.ORDER_PROCESS_2);
    super.update(order);
  }

  @Transactional
  public void updatePayment(Long id) {
    Order order = super.get(id);
    order.setOrderState(Constant.ORDER_STATE_3);
    order.setOrderProcess(Constant.ORDER_PROCESS_3);
    super.update(order);

    orderDetailService.updatePayment(id);
  }

  private Specification<Order> where(final Order order) {
    return new Specification<Order>() {
      @Override
      public Predicate toPredicate(Root<Order> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        List<Predicate> predicates = new ArrayList<Predicate>();

        return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
      }
    };
  }


}
